package com.stars.easyms.redis.interceptor;

import com.stars.easyms.redis.annotion.RedisHashSet;
import com.stars.easyms.redis.exception.RedisInterceptorException;
import com.stars.easyms.base.util.GenericTypeUtil;
import com.stars.easyms.base.util.ReflectUtil;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>className: RedisHashSetInterceptor</p>
 * <p>description: RedisHashSet注解拦截器</p>
 *
 * @author guoguifang
 * @version 1.2.1
 * @date 2019-03-18 14:39
 */
public class RedisHashSetInterceptor extends AbstractRedisInterceptor<RedisHashSet> {

    @Override
    protected Object invoke(MethodInvocation methodInvocation, RedisHashSet redisHashSet) throws RedisInterceptorException {
        Object result = proceed(methodInvocation);
        if (isEnabled() && result != null) {
            Method pointMethod = methodInvocation.getMethod();
            Class<?> returnType = pointMethod.getReturnType();
            Type genericReturnType = pointMethod.getGenericReturnType();
            Set<String> hashKeySet = getRedisHashKey(methodInvocation);
            int hashKeySetSize = hashKeySet.size();
            boolean isInvalidReturnType = hashKeySetSize > 1
                    && (!Map.class.isAssignableFrom(returnType)
                    || !String.class.isAssignableFrom(GenericTypeUtil.getGenericClass(genericReturnType, 0)));
            if (isInvalidReturnType) {
                logger.error("Method '{}' when have more than one redis hashKey, returnType should be Map<String, T>!",
                        ReflectUtil.getMethodFullName(pointMethod));
                return result;
            }

            boolean resetExpire = redisHashSet.resetExpire();
            long currRemainingExpireMills = -1;
            String redisKey = getRedisKey(methodInvocation, redisHashSet.group());
            if (hashKeySetSize == 1) {
                easyMsRedisTemplate.hashSet(redisKey, (String) hashKeySet.toArray()[0], result);
                // 如果不需要重置过期时间，则需要查询原剩余时间用于判断后续的操作，如果原剩余时间小于等于0即使未设置重置过期时间也需要重新设置过期时间
                if (!resetExpire) {
                    currRemainingExpireMills = easyMsRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS);
                }
            } else {
                // 1.若需要重写整个hash的所有值，需要先获取到过期时间，等set后再把过期时间恢复
                // 2.如果不需要重置过期时间，则需要查询原剩余时间用于判断后续的操作，如果原剩余时间小于等于0即使未设置重置过期时间也需要重新设置过期时间
                if (redisHashSet.override() || !resetExpire) {
                    currRemainingExpireMills = easyMsRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS);
                    if (redisHashSet.override()) {
                        easyMsRedisTemplate.delete(redisKey);
                    }
                }
                easyMsRedisTemplate.hashSet(redisKey, result);
            }

            // 重置过期时间
            resetExpire(methodInvocation, redisKey, resetExpire, currRemainingExpireMills, redisHashSet.expire());
        }
        return result;
    }
}